package nl.han.ica.ap.searchengine.server.crawling;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Observable;

import nl.han.ica.ap.searchengine.shared.sdo.Webpage;

/**
  * This object crawls a single url in a seperate thread. Anyone interested in
  * the result of the crawl has to implement the Observer interface and listen
  * to this object.
  * 
  * <p>To start the process of the UrlCrawler, you have to call its {@link #run()}
  * method. This will start the process of crawling the given webpage and creating
  * a functional Webpage object for its observers. If any Exception is thrown during
  * the execution, this object will instead return null.
  * 
  * <p>It notifies its observers with a {@link Webpage} object with the url and content
  * attributes filled. The pagerank attribute will remain empty untill a designated
  * class calculates it. (Calculating the Pagerank value of a webpage requires that
  * all the webpages are available for the calculation, since at this stage, we're
  * still indexing webpages we cannot perform that calculation.
  * 
  * @author W. ter Berg
  */
public class UrlCrawler extends Observable implements Runnable {

	private boolean running;
	private final String url;
	
	/**
	  * Creates a new UrlCrawler object with a given url, this url can, but should not
	  * be, null.
	  * 
	  * @param url The url that this object should visit.
	  */
	public UrlCrawler(final String url) {
		this.url = url;
	}
	
	/**
	  * Starts the process of visiting the given url and storing its contents in a
	  * {@link Webpage} object and sending that object to its observers.
	  */
	public final void run() {
		this.running = true;
		Webpage result = null;
		
		while (this.running) {
			try {
				result = new Webpage(this.url, this.loadHtml(new URL(this.url)));
			} catch (IOException ioe) {
				// Something went wrong crawling this website, so we stop the thread 
				// and return a null object and let the observer deal with it.
			}
			this.running = false;
		}
		
		this.setChanged();
		this.notifyObservers(result);
	}
	
	private String loadHtml(final URL url) throws IOException {
		StringBuffer html = new StringBuffer();
		URLConnection request = url.openConnection();
		InputStreamReader inputStream = new InputStreamReader(request.getInputStream());
		BufferedReader responseStream = new BufferedReader(inputStream);
		
		try {
			String line = null;
			
			while ((line = responseStream.readLine()) != null) {
				html.append(line + "\n");
			}
		} finally {
			responseStream.close();
			inputStream.close();
		}
		
		return html.toString();
	}
	
}
